#include "stdafx.h"

#include "Logic.h"
#include "MsgBuf.h"
#include "Network.h"
#include "msgproc.h"
#include <map>
#include <assert.h>

#pragma comment(lib, "winmm")

extern CNetwork* g_pNetwork;

struct Player
{
    DWORD connIndex;
    int x;
    int y;
	int isHost;
};

char g_Buff[10240] = {0};
int g_BuffPos = 0;
bool g_SyncStarted = false;

typedef std::map<DWORD, Player*> PlayerMap;

PlayerMap g_Players;

void BroadcastToAll(const CMsgTyped& msg)
{
    PlayerMap::iterator it = g_Players.begin();

    for (; it != g_Players.end(); ++it)
    {
        g_pNetwork->Send(it->first, (char*)msg.GetData(), msg.GetLength());
    }
}

void BroadcastToAllExcept(const CMsgTyped& msg, DWORD dwIndex)
{
    PlayerMap::iterator it = g_Players.begin();

    for (; it != g_Players.end(); ++it)
    {
        if (dwIndex != it->first)
        {
            g_pNetwork->Send(it->first, (char*)msg.GetData(), msg.GetLength());
        }
    }
}

enum MessageID
{
	MSGID_CREATE_PLAYER,
	MSGID_DESTROY_PLAYER,
	MSGID_START_GAME,
	MSGID_SYNC,
	MSGID_PING,
	MSGID_REG_PLAYER,
	MSGID_PLAYER_COUNT,
};

void CreatePlayer(DWORD dwIndex)
{
	Player* player = new Player();

	player->isHost = FALSE;
	player->connIndex = dwIndex;
	player->x = rand() % 80;
	player->y = rand() % 60;

	g_Players[dwIndex] = player;
}

void StartSync()
{
	PlayerMap::iterator it = g_Players.begin();
	for (; it != g_Players.end(); ++it)
	{
		Player* p = it->second;

		PlayerMap::iterator it2 = g_Players.begin();
		for (; it2 != g_Players.end(); ++it2)
		{
			CMsgTyped msg;

			msg.SetInt(MSGID_CREATE_PLAYER);
			msg.SetInt(it2->first == p->connIndex);
			msg.SetInt(p->connIndex);
			msg.SetInt(p->x);
			msg.SetInt(p->y);
			msg.SetInt(p->isHost);
			g_pNetwork->Send(it2->first, (char*)msg.GetData(), msg.GetLength());
		}
	}

	CMsgTyped msg;
	msg.SetInt(MSGID_START_GAME);
	BroadcastToAll(msg);

	g_SyncStarted = true;

	printf("Sync started\n");
}

void BroadcastPlayerCount()
{
	CMsgTyped msg;
	msg.SetInt(MSGID_PLAYER_COUNT);
	msg.SetInt(g_Players.size());
	BroadcastToAll(msg);
}

void OnConnect(DWORD dwIndex)
{
	printf("OnConnect %d\n", dwIndex);

	if (g_SyncStarted)
	{
		g_pNetwork->CloseConnection(dwIndex);
	}
}

void OnDisconnect(DWORD dwIndex)
{
	if (g_Players.find(dwIndex) != g_Players.end())
	{
		Player* player = g_Players[dwIndex];

		delete player;

		g_Players.erase(dwIndex);

		CMsgTyped msg;
		msg.SetInt(MSGID_DESTROY_PLAYER);
		msg.SetInt(dwIndex);
		BroadcastToAll(msg);

		BroadcastPlayerCount();

		printf("OnDisconnect %d \n", dwIndex);
	}

	if (g_Players.size() == 0)
	{
		g_SyncStarted = false;

		printf("Sync stoped\n");
	}
}

void OnReceive(DWORD dwIndex, char *pMsg, DWORD dwLen)
{
    CMsgTyped msg(dwLen, pMsg);

	UI32 msgID = msg.IntVal();

	if (msgID == MSGID_REG_PLAYER)
	{
		CreatePlayer(dwIndex);

		BroadcastPlayerCount();
	}
	else if (msgID == MSGID_SYNC)
	{
		UI32 broadcast = msg.IntVal();

		if (broadcast)
		{
			assert(false);
		}
		else
		{
			UI32 instID = 0xEF;
			memcpy(g_Buff + g_BuffPos, &instID, 4);
			g_BuffPos += 4;

			const char* data = (const char*)msg.GetData();

			memcpy(g_Buff + g_BuffPos, data + 10, msg.GetLength() - 10);
			g_BuffPos += msg.GetLength() - 10;
		}
	}
	else if (msgID == MSGID_PING)
	{
		g_pNetwork->Send(dwIndex, (char*)msg.GetData(), msg.GetLength());
	}
	else if (msgID == MSGID_START_GAME)
	{
		if (!g_SyncStarted)
		{
			StartSync();
		}
	}
}

static int STEP_COUNTER = 0;

void Step()
{
	UI32 instID = 0xFE;
	memcpy(g_Buff + g_BuffPos, &instID, 4);
	g_BuffPos += 4;

	STEP_COUNTER++;

	if (STEP_COUNTER == 10)
	{
		STEP_COUNTER = 0;

		CMsgTyped msg;
		msg.SetInt(MSGID_SYNC);
		msg.SetInt(TRUE);
		msg.Append(g_Buff, g_BuffPos);
		BroadcastToAll(msg);

		g_BuffPos = 0;
	}
}

void MainLoop()
{
	static DWORD last = timeGetTime();

	DWORD now = timeGetTime();

	if (now - last > 20)
	{
		last = now;

		Step();
	}
	else
	{
		Sleep(0);
	}
}